/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： bsp_RTC.c
** 模块名称： KD986_New仪表时钟RTC模块
** 版 本 号： V1.0
** 作    者： 蒲磊
** 
** 修改记录： 版本     修改人      时间         修改内容
**
******************************************************************************/
 
/******************************************************************************
* 头文件
******************************************************************************/
#include "bsp_RTC.h"
/******************************************************************************
* 本文件宏定义 ('#define')                             
******************************************************************************/
 
/******************************************************************************
* 本文件类型定义 ('typedef')                                         
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/
static uint8_t RTC_Week_Get(uint16_t year, uint8_t month, uint8_t day);

/******************************************************************************
* 全局变量定义 
******************************************************************************/
/* monthly correction data sheet */
const uint8_t table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};

/* monmonth data table of common year */
const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/
 
 
/******************************************************************************
** 功  能：RTC外设初始化
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vBsp_RTC_Init(void)
{
	calendar_type calendar;
	/* enable pwc and bpr clocks */
	crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);

	/* enable the battery-powered domain write operations */
	pwc_battery_powered_domain_access(TRUE);

	/* check if rtc is initialized */
	if(bpr_data_read(BPR_DATA1) != 0x1234)
	{
		/*默认日期：2022-01-01 00：00：00*/
		calendar.year  = 2022;
		calendar.month = 1;
		calendar.date	= 1;
		calendar.hour	= 0;
		calendar.min	= 0;
		calendar.sec	= 0;
		
		/* reset battery-powered domain register */
		bpr_reset();

		/* enable the lext osc */
		crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
		/* wait lext is ready */
		while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET);
		/* select the rtc clock source */
		crm_rtc_clock_select(CRM_RTC_CLOCK_LEXT);

		/* enable rtc clock */
		crm_rtc_clock_enable(TRUE);

		/* wait for rtc registers update */
		rtc_wait_update_finish();

		/* wait for the register write to complete */
		rtc_wait_config_finish();

		/* set rtc divider: set rtc period to 1sec */
		rtc_divider_set(32767);

		/* wait for the register write to complete */
		rtc_wait_config_finish();

		/* set time */
		ucRTC_Time_Set(&calendar);

		/* writes data to bpr register */
		bpr_data_write(BPR_DATA1, 0x1234);

	}
	else
	{
		/* wait for rtc registers update */
		rtc_wait_update_finish();

		/* wait for the register write to complete */
		rtc_wait_config_finish();
   
	}
}



/******************************************************************************
** 功  能：判断是闰年还是平年
** 参  数：年份
** 返回值：0-平年，1-闰年
** 备  注：- month       1  2  3  4  5  6  7  8  9  10 11 12
**         - leap year   31 29 31 30 31 30 31 31 30 31 30 31
**         - common year 31 28 31 30 31 30 31 31 30 31 30 31
******************************************************************************/
uint8_t ucRTC_Is_Leap_Year(uint16_t year)
{
	if(year % 4 == 0)
	{
		if(year % 100 == 0)
		{
			if(year % 400 == 0)
			{
				return 1;
			}
			else
			{
				return 0;
			}
		}
		else
		{
			return 1;
		}
	}
	else
	{
		return 0;
	}
}


/******************************************************************************
** 功  能：设置RTC日期及时间
** 参  数：calendar-日期结构体指针
** 返回值：0-设置成功，1-失败
** 备  注：the time basic : 1970.1.1
**         legitimate year: 1970 ~ 2099
******************************************************************************/
uint8_t ucRTC_Time_Set(calendar_type *calendar)
{
	uint32_t t;
	uint32_t seccount = 0;

	if(calendar->year < 1970 || calendar->year > 2099)
	{
		return 1;
	}

	for(t = 1970; t < calendar->year; t++)
	{
		if(ucRTC_Is_Leap_Year(t))
		{
			seccount += 31622400;
		}
		else
		{
			seccount += 31536000;
		}
	}

	calendar->month -= 1;

	for(t = 0; t < calendar->month; t++)
	{
		seccount += (uint8_t)mon_table[t] * 86400;

		if(ucRTC_Is_Leap_Year(calendar->year) && t == 1)
		{
			seccount += 86400;
		}
	}

	seccount += (uint8_t)(calendar->date - 1) * 86400;

	seccount += (uint8_t)calendar->hour * 3600;

	seccount += (uint8_t)calendar->min * 60;

	seccount += calendar->sec;

	/* enable pwc and bpr clocks */
	crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);

	/* enable write access to bpr domain */
	pwc_battery_powered_domain_access(TRUE);

	/* set the rtc counter value */
	rtc_counter_set(seccount);

	/* wait for the register write to complete */
	rtc_wait_config_finish();

	return 0;
}


/******************************************************************************
** 功  能：设置RTC闹钟时间
** 参  数：calendar-日期结构体指针
** 返回值：0-设置成功，1-失败
** 备  注：the time basic : 1970.1.1
**         legitimate year: 1970 ~ 2099
******************************************************************************/
uint8_t RTC_Alarm_Clock_Set(calendar_type *calendar)
{
	uint16_t t;
	uint32_t seccount = 0;

	if(calendar->year < 1970 || calendar->year > 2099)
	{
		return 1;
	}

	for(t = 1970; t < calendar->year; t++)
	{
		if(ucRTC_Is_Leap_Year(t))
		{
			seccount += 31622400;
		}
		else
		{
			seccount += 31536000;
		}
	}

	calendar->month -= 1;

	for(t = 0; t < calendar->month; t++)
	{
		seccount += (uint8_t)mon_table[t] * 86400;

		if(ucRTC_Is_Leap_Year(calendar->year) && t == 1)
		{
			seccount += 86400;
		}
	}

	seccount += (uint8_t)(calendar->date - 1) * 86400;
	seccount += (uint8_t)calendar->hour * 3600;
	seccount += (uint8_t)calendar->min * 60;
	seccount += calendar->sec;

	/* enable pwc and bpr clocks */
	crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);

	/* enable write access to bpr domain */
	pwc_battery_powered_domain_access(TRUE);

	/* set the rtc counter value */
	rtc_alarm_set(seccount);

	/* wait for the register write to complete */
	rtc_wait_config_finish();

	return 0;
}


/******************************************************************************
** 功  能：根据当前日期计算星期
** 参  数：year-年份，month-月，day-日
** 返回值：星期数
** 备  注：0代表星期天
******************************************************************************/
static uint8_t RTC_Week_Get(uint16_t year, uint8_t month, uint8_t day)
{
	uint16_t temp2;
	uint8_t yearh, yearl;

	yearh = year / 100;
	yearl = year % 100;

	if(yearh > 19)
	{
		yearl += 100;
	}

	temp2 = yearl + yearl / 4;
	temp2 = temp2 % 7;
	temp2 = temp2 + day + table_week[month - 1];

	if(yearl % 4 == 0 && month < 3)
	{
		temp2--;
	}

	return(temp2 % 7);
}

/******************************************************************************
** 功  能：获取RTC日期及时间
** 参  数：calendar-日期结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
void RTC_Time_Get(calendar_type *calendar)
{
	static uint16_t daycnt = 0;
	uint32_t timecount = 0;
	uint32_t temp = 0;
	uint32_t temp1 = 0;
	static calendar_type calendar_temp;

	timecount = rtc_counter_get();
	temp = timecount / 86400;

	if(daycnt != temp)
	{
		daycnt = temp;
		temp1 = 1970;

		while(temp >= 365)
		{
			if(ucRTC_Is_Leap_Year(temp1))
			{
				if(temp >= 366)
				{
					temp -= 366;
				}
				else
				{
					temp1++;
					break;
				}
			}
			else
			{
				temp -= 365;
			}

			temp1++;
		}

		calendar_temp.year = temp1;
		temp1 = 0;

		while(temp >= 28)
		{
			if(ucRTC_Is_Leap_Year(calendar_temp.year) && temp1 == 1)
			{
				if(temp >= 29)
					{
					temp -= 29;
				}
				else
				{
					break;
				}
			}
			else
			{
				if(temp >= mon_table[temp1])
				{
					temp -= mon_table[temp1];
				}
				else
				{
					break;
				}
			}

			temp1++;
		}

		calendar_temp.month = temp1 + 1;
		calendar_temp.date = temp + 1;
	}

	temp = timecount % 86400;
	calendar->year = calendar_temp.year;
	calendar->month = calendar_temp.month;
	calendar->date = calendar_temp.date;
	calendar->hour = temp / 3600;
	calendar->min = (temp % 3600) / 60;
	calendar->sec = (temp % 3600) % 60;
	calendar->week = RTC_Week_Get(calendar->year, calendar->month, calendar->date);
}
